package com.example.dictdemo.service.impl;

import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.dictdemo.common.constant.CacheConstant;
import com.example.dictdemo.common.constant.DataBaseConstant;
import com.example.dictdemo.common.utils.ConvertUtils;
import com.example.dictdemo.common.utils.ResourceUtil;
import com.example.dictdemo.common.utils.SqlInjectionUtil;
import com.example.dictdemo.mapper.SysDictMapper;
import com.example.dictdemo.model.SysDict;
import com.example.dictdemo.model.SysDictItem;
import com.example.dictdemo.model.vo.DictModel;
import com.example.dictdemo.model.vo.DictModelMany;
import com.example.dictdemo.service.ISysBaseAPI;
import com.example.dictdemo.service.ISysDictService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * isys字典服务impl
 *
 * @author dlp
 * @date 2024/08/20
 */
@Service
@Slf4j
public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> implements ISysDictService {
    @Autowired
    private SysDictMapper sysDictMapper;

    @Lazy
    @Autowired
    private ISysBaseAPI sysBaseAPI;
    /**
     * 通过查询指定code 获取字典值text
     * @param code
     * @param key
     * @return
     */

    @Override
    @Cacheable(value = CacheConstant.SYS_DICT_CACHE,key = "#code+':'+#key", unless = "#result == null ")
    public String queryDictTextByKey(String code, String key) {
        log.debug("无缓存dictText的时候调用这里！");
        return sysDictMapper.queryDictTextByKey(code, key);
    }
    /**
     * 可通过多个字典code查询翻译文本
     *
     * @param dictCodeList 多个字典code
     * @param keys         数据列表
     * @return
     */
    @Override
    public Map<String, List<DictModel>> queryManyDictByKeys(List<String> dictCodeList, List<String> keys) {
        List<DictModelMany> list = sysDictMapper.queryManyDictByKeys(dictCodeList, keys);
        Map<String, List<DictModel>> dictMap = new HashMap(5);
        for (DictModelMany dict : list) {
            List<DictModel> dictItemList = dictMap.computeIfAbsent(dict.getDictCode(), i -> new ArrayList<>());
            dictItemList.add(new DictModel(dict.getValue(), dict.getText()));
        }
        //update-begin-author:taoyan date:2022-7-8 for: 系统字典数据应该包括自定义的java类-枚举
        Map<String, List<DictModel>> enumRes = ResourceUtil.queryManyDictByKeys(dictCodeList, keys);
        dictMap.putAll(enumRes);
        //update-end-author:taoyan date:2022-7-8 for: 系统字典数据应该包括自定义的java类-枚举
        return dictMap;
    }

    /**
     * 通过查询指定table的 text code key 获取字典值
     *
     * @param table
     * @param text
     * @param code
     * @param key
     * @return
     */
    @Override
    @Cacheable(value = CacheConstant.SYS_DICT_TABLE_CACHE, unless = "#result == null ")
    public String queryTableDictTextByKey(String table,String text,String code, String key,String dataSource) {
        log.debug("无缓存dictTable的时候调用这里！");

        String str = table+","+text+","+code;
//        // 【QQYUN-6533】表字典白名单check
//        sysBaseAPI.dictTableWhiteListCheckByDict(table, text, code);
//        // 1.表字典黑名单check
//        if(!dictQueryBlackListHandler.isPass(str)){
//            log.error(dictQueryBlackListHandler.getError());
//            return null;
//        }
        boolean isCustomDataSource = ConvertUtils.isNotEmpty(dataSource);
        //解决分布式下表字典跨库无法查询问题------------
        // 切换为字典表的数据源
        if (isCustomDataSource) {
            DynamicDataSourceContextHolder.push(dataSource);
        }
        // 2.sql注入check
        SqlInjectionUtil.filterContentMulti(table, text, code, key);

        // 3.针对采用 ${}写法的表名和字段进行转义和check
        table = SqlInjectionUtil.getSqlInjectTableName(table);
        text = SqlInjectionUtil.getSqlInjectField(text);
        code = SqlInjectionUtil.getSqlInjectField(code);

        List<DictModel> dictModeList = sysDictMapper.queryTableDictByKeysAndFilterSql(table, text, code, null, Arrays.asList(key));
        if(CollectionUtils.isEmpty(dictModeList)){
            return null;
        }else{
            return dictModeList.get(0).getText();
        }
    }

    /**
     * 通过查询指定table的 text code key 获取字典值，可批量查询
     *
     * @param table
     * @param text
     * @param code
     * @param dataSource 数据源
     * @return
     */
    @Override
    public List<DictModel> queryTableDictTextByKeys(String table, String text, String code, List<String> codeValues, String dataSource) {
        String str = table+","+text+","+code;
        // 是否自定义数据源
        boolean isCustomDataSource = ConvertUtils.isNotEmpty(dataSource);
        // 如果是自定义数据源就不检查表字典白名单
        if (!isCustomDataSource) {
            // 【QQYUN-6533】表字典白名单check
//            sysBaseAPI.dictTableWhiteListCheckByDict(table, text, code);
//            // 1.表字典黑名单check
//            if (!dictQueryBlackListHandler.isPass(str)) {
//                log.error(dictQueryBlackListHandler.getError());
//                return null;
//            }
        }

        // 2.分割SQL获取表名和条件
        String filterSql = null;
        if(table.toLowerCase().indexOf(DataBaseConstant.SQL_WHERE)>0){
            String[] arr = table.split(" (?i)where ");
            table = arr[0];
            filterSql = arr[1];
        }

        // 3.SQL注入check
        SqlInjectionUtil.filterContentMulti(table, text, code);
        SqlInjectionUtil.specialFilterContentForDictSql(filterSql);

        // 4.针对采用 ${}写法的表名和字段进行转义和check
        table = SqlInjectionUtil.getSqlInjectTableName(table);
        text = SqlInjectionUtil.getSqlInjectField(text);
        code = SqlInjectionUtil.getSqlInjectField(code);

        //解决分布式下表字典跨库无法查询问题------------
        // 切换为字典表的数据源
        if (isCustomDataSource) {
            DynamicDataSourceContextHolder.push(dataSource);
        }
        List<DictModel> restData = sysDictMapper.queryTableDictByKeysAndFilterSql(table, text, code, filterSql, codeValues);
        // 清理自定义的数据源
        if (isCustomDataSource) {
            DynamicDataSourceContextHolder.clear();
        }
        return restData;
        //update-end---author:chenrui ---date:20231221  for：[issues/#5643]解决分布式下表字典跨库无法查询问题------------
        //update-end-author:taoyan date:20220113 for: @dict注解支持 dicttable 设置where条件
    }

    /**
     * 通过查询指定table的 text code key 获取字典值，包含value
     *
     * @param table 表名
     * @param text
     * @param code
     * @param keys
     * @return
     */
    @Override
    public List<String> queryTableDictByKeys(String table, String text, String code, String keys) {
//        String str = table+","+text+","+code;
//        // 【QQYUN-6533】表字典白名单check
//        sysBaseAPI.dictTableWhiteListCheckByDict(table, text, code);
//        // 1.表字典黑名单check
//        if(!dictQueryBlackListHandler.isPass(str)){
//            log.error(dictQueryBlackListHandler.getError());
//            return null;
//        }

        return this.queryTableDictByKeys(table, text, code, keys, true);
    }

    /**
     * 通过查询指定table的 text code 获取字典，包含text和value
     * dictTableCache采用redis缓存有效期10分钟
     * @param table
     * @param text
     * @param code
     * @param codeValuesStr (逗号分隔)
     * @param delNotExist 是否移除不存在的项，默认为true，设为false如果某个key不存在数据库中，则直接返回key本身
     * @return
     */
    @Override
    public List<String> queryTableDictByKeys(String table, String text, String code, String codeValuesStr, boolean delNotExist) {
//        if(oConvertUtils.isEmpty(codeValuesStr)){
//            return null;
//        }
//
//        //1.分割sql获取表名 和 条件sql
//        String filterSql = null;
//        if(table.toLowerCase().indexOf("where")!=-1){
//            String[] arr = table.split(" (?i)where ");
//            table = arr[0];
//            filterSql = arr[1];
//        }
//
//        // 2.SQL注入check
//        SqlInjectionUtil.filterContentMulti(table, text, code);
//        SqlInjectionUtil.specialFilterContentForDictSql(filterSql);
//
//        String str = table+","+text+","+code;
//        // 【QQYUN-6533】表字典白名单check
//        sysBaseAPI.dictTableWhiteListCheckByDict(table, text, code);
//        // 3.表字典黑名单check
//        if(!dictQueryBlackListHandler.isPass(str)){
//            log.error(dictQueryBlackListHandler.getError());
//            return null;
//        }
//
//        // 4.针对采用 ${}写法的表名和字段进行转义和check
//        table = SqlInjectionUtil.getSqlInjectTableName(table);
//        text = SqlInjectionUtil.getSqlInjectField(text);
//        code = SqlInjectionUtil.getSqlInjectField(code);
//
//        //字典条件值
//        String[] codeValues = codeValuesStr.split(",");
//        // 5.查询字典数据
//        List<DictModel> dicts = sysDictMapper.queryTableDictByKeysAndFilterSql(SqlInjectionUtil.getSqlInjectTableName(table),
//                SqlInjectionUtil.getSqlInjectField(text), SqlInjectionUtil.getSqlInjectField(code), filterSql, Arrays.asList(codeValues));

//        List<String> texts = new ArrayList<>(dicts.size());
//        // 6.查询出来的顺序可能是乱的，需要排个序
//        for (String conditionalVal : codeValues) {
//            List<DictModel> res = dicts.stream().filter(i -> conditionalVal.equals(i.getValue())).collect(Collectors.toList());
//            if (res.size() > 0) {
//                texts.add(res.get(0).getText());
//            } else if (!delNotExist) {
//                texts.add(conditionalVal);
//            }
//        }
        return null;
//        return texts;
    }

}
